#include "StdAfx.h"
#include "StockDataDownloader.h"
#include "StockDataLoader.h"
#include "utility.h"
#include "micro.h"
#include <stdlib.h>

using namespace std;

CStockDataDownloader::CStockDataDownloader(void)
	: mCurl(NULL), mErrorCode(CURLE_FAILED_INIT), mResponseErrCode(-1)
{
	mBaseDir = CacheDataDir;
	mCurl = curl_easy_init();
	if (mCurl == NULL)
		return;
	if (!SetOption(CURLOPT_WRITEFUNCTION, data_callback))
		return;
	if (!SetOption(CURLOPT_WRITEDATA, &mBuffer))
		return;
	if (!SetOption(CURLOPT_NOSIGNAL, 1))
		return;
	if (!SetOption(CURLOPT_TIMEOUT, 10))
		return;

	mErrorCode = CURLE_OK;
}

CStockDataDownloader::~CStockDataDownloader(void)
{
	if (mCurl)
	{
		curl_easy_cleanup(mCurl);
		mCurl = NULL;
	}
}

size_t CStockDataDownloader::data_callback(char *data, size_t size, size_t nmemb, void * mp)
{
	uint32_t totalSize = size * nmemb;
	string& buffer = *((string* )mp);
	buffer.append(data, totalSize);
	return totalSize;
}

bool CStockDataDownloader::Download(const std::string& stockID,
	const DateType& beginDate,
	const DateType& endDate,
	const std::string& fileName/* = ""*/)
{
	string url = GenerateUrl(stockID, beginDate, endDate, YAHOO_SOURCE);
	string realFileName(fileName);
	if (realFileName.empty())
	{
		realFileName = mBaseDir + stockID + ".csv";
	}
	bool ret = DownloadURL(url);
	if (ret)
	{
		WriteToFile(realFileName, mBuffer);
	}
	return ret;
}

bool CStockDataDownloader::DownloadFromSina(const std::string& stockID,
	const DateType& beginDate,
	const DateType& endDate,
	const std::string& fileName/* = ""*/)
{
	string url = GenerateUrl(stockID, beginDate, endDate, SINA_SOURCE);
	string realFileName(fileName);
	if (realFileName.empty())
	{
		realFileName = mBaseDir + stockID + ".csv";
	}
	bool ret = DownloadURL(url); //not write to file, we need to write table title first
	if (ret)
	{
		std::string outputString = "Date,Open,High,Close,Low,Volume\n";
		outputString += mBuffer;
		WriteToFile(realFileName, outputString);
	}
	return ret;
}

double CStockDataDownloader::GetStockPublishPrice(const std::string& stockID)
{
	DateType beginDate(1900, 1, 1);
	DateType endDate = DateType::GetDate(0);
	string url = GenerateUrl(stockID, beginDate, endDate);
	double publishPrice = 0.0;
	bool ret = DownloadURL(url);
	if (ret)
	{
		CStockDataLoader dataLoader;
		dataLoader.LoadFromString(mBuffer, true);
		StockData stockData = dataLoader.GetStockData();
		if (stockData.dataVector.size() > 0)
		{
			publishPrice = (*stockData.dataVector.rbegin()).openPrice;
		}
	}
	return publishPrice;
}

bool CStockDataDownloader::DownloadURL(const std::string& url)
{
	bool ret(false);
	if(mCurl)
	{
		try
		{
			ret = Get(url.c_str());
			ret = (mResponseErrCode == 200);
		}
		catch (...)
		{}
	}
	return ret;
}

bool CStockDataDownloader::SetUrl(const char* url)
{
	return SetOption(CURLOPT_URL, url);
}

bool CStockDataDownloader::Perform()
{
	mBuffer.clear();
	mResponseErrCode = -1;
	CURLcode ret = curl_easy_perform(mCurl);
	mErrorCode = ret;
	if(mErrorCode == CURLE_OK)
	{
		curl_easy_getinfo(mCurl, CURLINFO_RESPONSE_CODE , &mResponseErrCode);
	}
	return (mErrorCode == CURLE_OK);
}

std::string CStockDataDownloader::GenerateUrl(const std::string& stockID,
											  const DateType& beginDate,
											  const DateType& endDate,
											  ESourceType sourceType/* = YAHOO_SOURCE*/)
{
	string url;
	DEFINE_TEMP_BUFFER(buffer);
	if (sourceType == YAHOO_SOURCE)
	{
		url = BaseUrlOfYahooSource;
		sprintf_s(buffer, TEMP_BUFFER_SIZE, "s=%s&a=%d&b=%d&c=%d&d=%d&e=%d&f=%d&g=d&ignore=.cvs",
											stockID.c_str(), beginDate.month - 1, beginDate.date, beginDate.year,
											endDate.month - 1, endDate.date, endDate.year);
	}
	else if (sourceType == SINA_SOURCE)
	{
		url = BaslUrlOfSinaSource;
		std::string stockIDOfSina;
		std::vector<std::string> splitResult = StringSplitter(stockID, ".");
		if (splitResult.size() == 2)
		{
			if (splitResult[1] == "SS")
			{
				stockIDOfSina = std::string("sh") + splitResult[0];
			}
			else if (splitResult[1] == "SZ")
			{
				stockIDOfSina = std::string("sz") + splitResult[0];
			}
		}
		else
		{
			stockIDOfSina = stockID;
		}
		sprintf_s(buffer, TEMP_BUFFER_SIZE, "symbol=%s&end_date=%s&begin_date=%s&type=plain",
											stockIDOfSina.c_str(), endDate.ToString().c_str(), beginDate.ToString().c_str());
	}
	
	url += buffer;
	return url;
}